package com.ruoyi.system.service.impl;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.system.domain.Project;
import com.ruoyi.system.dto.ItemAddDTO;
import com.ruoyi.system.dto.ItemUpdateDTO;
import com.ruoyi.system.dto.ItemCompleteDTO;
import com.ruoyi.system.dto.ConstructionProjectItemDTO;
import com.ruoyi.system.entity.ConstructionProjectItemDO;
import com.ruoyi.system.entity.ConstructionProjectStageRelDO;
import com.ruoyi.system.mapper.ConstructionItemMapper;
import com.ruoyi.system.service.IConstructionItemService;
import com.ruoyi.system.service.IProjectStageService;
import com.ruoyi.system.mapper.ProjectMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.LinkedHashMap;
import java.util.Collections;

/**
 * 施工事项管理Service实现类
 */
@Service
public class ConstructionItemServiceImpl extends ServiceImpl<ConstructionItemMapper, ConstructionProjectItemDO> implements IConstructionItemService {

    @Resource
    private ConstructionItemMapper constructionItemMapper;

    @Resource
    private IProjectStageService stageService;

    @Resource
    private ProjectMapper projectMapper;

    @Override
    public List<ConstructionProjectItemDTO> getItemsByStageId(Long projectId, Long stageId) {
        if (stageId == null) {
            throw new ServiceException("阶段ID不能为空");
        }

        List<ConstructionProjectItemDO> items = constructionItemMapper.selectList(
                new LambdaQueryWrapper<ConstructionProjectItemDO>()
                        .eq(ConstructionProjectItemDO::getStageId, stageId)
                        .eq(ConstructionProjectItemDO::getProjectId, projectId)
                        .eq(ConstructionProjectItemDO::getIsDeleted, 0)
                        .orderByAsc(ConstructionProjectItemDO::getStartTime)
        );

        return items.stream().map(this::convertToDTO).collect(Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean addItem(ItemAddDTO itemAddDTO) {
        ConstructionProjectItemDO item = new ConstructionProjectItemDO();
        item.setProjectId(itemAddDTO.getProjectId());
        item.setStageId(itemAddDTO.getStageId());
        item.setItemName(itemAddDTO.getItemName());
        item.setStartTime(itemAddDTO.getStartTime());
        item.setEndTime(itemAddDTO.getEndTime());
        item.setAcceptDesc(itemAddDTO.getAcceptDesc());

        // 处理验收图片
        if (itemAddDTO.getAcceptImages() != null && !itemAddDTO.getAcceptImages().isEmpty()) {
            item.setAcceptImages(JSON.toJSONString(itemAddDTO.getAcceptImages()));
        }

        // 计算工期天数
        if (itemAddDTO.getStartTime() != null && itemAddDTO.getEndTime() != null) {
            item.setDurationDays((int) ChronoUnit.DAYS.between(
                    itemAddDTO.getStartTime(), itemAddDTO.getEndTime()) + 1);
        }

        item.setCompletionStatus(itemAddDTO.getCompletionStatus()); // 默认为未开始
        item.setOwnerCoordination(itemAddDTO.getOwnerCoordination());
        item.setIsAccepted(0); // 默认为未验收
        item.setRemark(itemAddDTO.getRemark());
        item.setIsDeleted(0);
        item.setCreateTime(LocalDateTime.now());
        item.setUpdateTime(LocalDateTime.now());

        return constructionItemMapper.insert(item) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteItem(Long itemId) {
        if (itemId == null) {
            throw new ServiceException("事项ID不能为空");
        }

        ConstructionProjectItemDO item = constructionItemMapper.selectById(itemId);
        if (item == null || item.getIsDeleted() == 1) {
            throw new ServiceException("事项不存在");
        }

        // 逻辑删除
        item.setIsDeleted(1);
        item.setUpdateTime(LocalDateTime.now());
        return constructionItemMapper.deleteById(item) > 0;
    }

    @Override
    public boolean hasUnfinishedItems(Long projectId, Long stageId) {
        if (stageId == null) {
            return false;
        }

        // 查询是否已完成的事项数量
        long count = constructionItemMapper.selectCount(
                new LambdaQueryWrapper<ConstructionProjectItemDO>()
                        .eq(ConstructionProjectItemDO::getStageId, stageId)
                        .eq(ConstructionProjectItemDO::getProjectId, projectId)
                        .eq(ConstructionProjectItemDO::getIsDeleted, 0)
                        .lt(ConstructionProjectItemDO::getCompletionStatus, 2) // 0-未开始，1-进行中
        );

        return count > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateItem(ItemUpdateDTO itemUpdateDTO) {
        if (itemUpdateDTO.getId() == null) {
            throw new ServiceException("事项ID不能为空");
        }

        ConstructionProjectItemDO item = constructionItemMapper.selectById(itemUpdateDTO.getId());

        if (item == null || item.getIsDeleted() == 1) {
            throw new ServiceException("事项不存在");
        }

        item.setItemName(itemUpdateDTO.getItemName());
        item.setStartTime(itemUpdateDTO.getStartTime());
        item.setEndTime(itemUpdateDTO.getEndTime());
        item.setAcceptDesc(itemUpdateDTO.getAcceptDesc());
        
        // 处理验收图片
        if (itemUpdateDTO.getAcceptImages() != null && !itemUpdateDTO.getAcceptImages().isEmpty()) {
            item.setAcceptImages(JSON.toJSONString(itemUpdateDTO.getAcceptImages()));
        }
        
        item.setCompletionStatus(itemUpdateDTO.getCompletionStatus());
        item.setOwnerCoordination(itemUpdateDTO.getOwnerCoordination());
        item.setRemark(itemUpdateDTO.getRemark());
        item.setUpdateTime(LocalDateTime.now());
        // 重新计算工期天数
        if (itemUpdateDTO.getStartTime() != null && itemUpdateDTO.getEndTime() != null) {
            item.setDurationDays((int) ChronoUnit.DAYS.between(
                    itemUpdateDTO.getStartTime(), itemUpdateDTO.getEndTime()) + 1);
        }
        constructionItemMapper.updateById(item);
        Long projectId = item.getProjectId();
        Long stageId = item.getStageId();
        List<ConstructionProjectItemDO> list = this.lambdaQuery()
                .eq(ConstructionProjectItemDO::getProjectId, projectId)
                .eq(ConstructionProjectItemDO::getStageId, stageId)
                .eq(ConstructionProjectItemDO::getIsDeleted, 0)
                .list();
        if (!list.isEmpty()) {
            if(list.stream().allMatch(i -> i.getCompletionStatus() != null && i.getCompletionStatus() == 2)){
                LocalDate endTime = list.stream()
                        // 过滤掉startTime为null的元素
                        .map(ConstructionProjectItemDO::getEndTime)
                        // 提取startTime字段
                        .filter(Objects::nonNull)
                        // 找到最小（最早）的日期
                        .max(LocalDate::compareTo).orElse(null);
                stageService.lambdaUpdate()
                        .set(ConstructionProjectStageRelDO::getStageStatus, 2)
                        .set(ConstructionProjectStageRelDO::getEndTime, endTime)
                        .eq(ConstructionProjectStageRelDO::getProjectId, projectId)
                        .eq(ConstructionProjectStageRelDO::getStageId, stageId)
                        .update();
                
                // 阶段完成后自动触发推送验收消息
//                triggerAcceptanceChecklistPush(projectId, stageId);
            } else if(list.stream().anyMatch(i -> i.getCompletionStatus() != null && i.getCompletionStatus() == 1)){
                LocalDate startTime = list.stream()
                        // 过滤掉startTime为null的元素
                        .map(ConstructionProjectItemDO::getStartTime)
                        // 提取startTime字段
                        .filter(Objects::nonNull)
                        // 找到最小（最早）的日期
                        .min(LocalDate::compareTo).orElse(null);
                stageService.lambdaUpdate()
                        .set(ConstructionProjectStageRelDO::getStageStatus, 1)
                        .set(ConstructionProjectStageRelDO::getStartTime, startTime)
                        .eq(ConstructionProjectStageRelDO::getProjectId, projectId)
                        .eq(ConstructionProjectStageRelDO::getStageId, stageId)
                        .update();
            }
        }
        return true;
    }

    @Override
    public List<ConstructionProjectItemDTO> listTodayPendingFollowUps(Long projectId, LocalDate today) {
        LocalDate base = today != null ? today : LocalDate.now();
        // 数据范围：管理员全部；设计师仅本人项目
        List<Long> allowedProjectIds = getAllowedProjectIds();
        if (!isAdmin() && allowedProjectIds.isEmpty()) {
            return java.util.Collections.emptyList();
        }
        List<ConstructionProjectItemDO> items = this.lambdaQuery()
                .eq(projectId != null, ConstructionProjectItemDO::getProjectId, projectId)
                .in(!isAdmin() && projectId != null, ConstructionProjectItemDO::getProjectId, allowedProjectIds)
                .eq(ConstructionProjectItemDO::getIsDeleted, 0)
                .lt(ConstructionProjectItemDO::getCompletionStatus, 2)
                .eq(ConstructionProjectItemDO::getEndTime, base)
                .orderByAsc(ConstructionProjectItemDO::getEndTime)
                .list();
        return items.stream().map(this::convertToDTO).collect(Collectors.toList());
    }

    @Override
    public List<ConstructionProjectItemDTO> listOverduePendingFollowUps(Long projectId, LocalDate today) {
        LocalDate base = today != null ? today : LocalDate.now();
        java.util.List<Long> allowedProjectIds = getAllowedProjectIds();
        if (!isAdmin() && allowedProjectIds.isEmpty()) {
            return java.util.Collections.emptyList();
        }
        List<ConstructionProjectItemDO> items = this.lambdaQuery()
                .eq(projectId != null, ConstructionProjectItemDO::getProjectId, projectId)
                .in(!isAdmin() && projectId == null, ConstructionProjectItemDO::getProjectId, allowedProjectIds)
                .eq(ConstructionProjectItemDO::getIsDeleted, 0)
                .lt(ConstructionProjectItemDO::getCompletionStatus, 2)
                .lt(ConstructionProjectItemDO::getEndTime, base)
                .orderByDesc(ConstructionProjectItemDO::getEndTime)
                .list();
        return items.stream().map(this::convertToDTO).collect(Collectors.toList());
    }

    @Override
    public List<ConstructionProjectItemDTO> listDueSoonPendingFollowUps(Long projectId, LocalDate today, int days) {
        LocalDate base = today != null ? today : LocalDate.now();
        int window = days > 0 ? days : 7;
        LocalDate end = base.plusDays(window);
        java.util.List<Long> allowedProjectIds = getAllowedProjectIds();
        if (!isAdmin() && allowedProjectIds.isEmpty()) {
            return java.util.Collections.emptyList();
        }
        List<ConstructionProjectItemDO> items = this.lambdaQuery()
                .eq(projectId != null, ConstructionProjectItemDO::getProjectId, projectId)
                .in(!isAdmin() && projectId == null, ConstructionProjectItemDO::getProjectId, allowedProjectIds)
                .in(!isAdmin() && projectId != null, ConstructionProjectItemDO::getProjectId, allowedProjectIds)
                .eq(ConstructionProjectItemDO::getIsDeleted, 0)
                .lt(ConstructionProjectItemDO::getCompletionStatus, 2)
                .ge(ConstructionProjectItemDO::getEndTime, base)
                .le(ConstructionProjectItemDO::getEndTime, end)
                .orderByAsc(ConstructionProjectItemDO::getEndTime)
                .list();
        return items.stream().map(this::convertToDTO).collect(Collectors.toList());
    }

    private boolean isAdmin() {
        return SecurityUtils.hasRole("ADMIN") || SecurityUtils.hasRole("ROLE_ADMIN");
    }

    private java.util.List<Long> getAllowedProjectIds() {
        if (isAdmin()) {
            return Collections.emptyList();
        }
        Long currentUserId = SecurityUtils.getUserId();
        return projectMapper.selectList(
                        new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<Project>()
                                .eq(Project::getDeleted, 0)
                                .eq(Project::getDesignerId, currentUserId)
                                .select(Project::getId)
                ).stream()
                .map(Project::getId)
                .collect(java.util.stream.Collectors.toList());
    }

    @Override
    public java.util.Map<String, Integer> calendarSummary(LocalDate month) {
        LocalDate base = month != null ? month : LocalDate.now();
        LocalDate monthStart = base.withDayOfMonth(1);
        LocalDate monthEnd = monthStart.plusMonths(1).minusDays(1);
        List<Long> allowedProjectIds = getAllowedProjectIds();
        if (!isAdmin() && allowedProjectIds.isEmpty()) {
            return Collections.emptyMap();
        }
        List<ConstructionProjectItemDO> items = this.lambdaQuery()
                .in(!isAdmin(), ConstructionProjectItemDO::getProjectId, allowedProjectIds)
                .eq(ConstructionProjectItemDO::getIsDeleted, 0)
                .lt(ConstructionProjectItemDO::getCompletionStatus, 2)
                .le(ConstructionProjectItemDO::getStartTime, monthEnd)
                .ge(ConstructionProjectItemDO::getEndTime, monthStart)
                .list();
        LinkedHashMap<String, Integer> summary = new LinkedHashMap<>();
        LocalDate cursor = monthStart;
        while (!cursor.isAfter(monthEnd)) {
            summary.put(cursor.toString(), 0);
            cursor = cursor.plusDays(1);
        }
        for (ConstructionProjectItemDO it : items) {
            LocalDate s = it.getStartTime() != null ? it.getStartTime() : monthStart;
            LocalDate e = it.getEndTime() != null ? it.getEndTime() : monthEnd;
            LocalDate from = s.isAfter(monthStart) ? s : monthStart;
            LocalDate to = e.isBefore(monthEnd) ? e : monthEnd;
            LocalDate d = from;
            while (!d.isAfter(to)) {
                String key = d.toString();
                summary.put(key, summary.getOrDefault(key, 0) + 1);
                d = d.plusDays(1);
            }
        }
        return summary;
    }

    @Override
    public List<ConstructionProjectItemDTO> calendarTodos(LocalDate date, Long projectId) {
        LocalDate target = date != null ? date : LocalDate.now();
        List<Long> allowedProjectIds = getAllowedProjectIds();
        if (!isAdmin() && allowedProjectIds.isEmpty()) {
            return Collections.emptyList();
        }
        List<ConstructionProjectItemDO> items = this.lambdaQuery()
                .eq(projectId != null, ConstructionProjectItemDO::getProjectId, projectId)
                .in(!isAdmin() && projectId != null, ConstructionProjectItemDO::getProjectId, allowedProjectIds)
                .eq(ConstructionProjectItemDO::getIsDeleted, 0)
                .lt(ConstructionProjectItemDO::getCompletionStatus, 2)
                .le(ConstructionProjectItemDO::getStartTime, target)
                .ge(ConstructionProjectItemDO::getEndTime, target)
                .orderByAsc(ConstructionProjectItemDO::getEndTime)
                .list();
        return items.stream().map(this::convertToDTO).collect(Collectors.toList());
    }

    /**
     * 转换实体为DTO
     */
    private ConstructionProjectItemDTO convertToDTO(ConstructionProjectItemDO item) {
        ConstructionProjectItemDTO dto = new ConstructionProjectItemDTO();
        dto.setId(item.getId());
        dto.setProjectId(item.getProjectId());
        dto.setStageId(item.getStageId());
        dto.setItemName(item.getItemName());
        dto.setStartTime(item.getStartTime());
        dto.setEndTime(item.getEndTime());
        dto.setDurationDays(item.getDurationDays());
        dto.setCompletionStatus(item.getCompletionStatus());
        dto.setOwnerCoordination(item.getOwnerCoordination());
        dto.setIsAccepted(item.getIsAccepted());
        dto.setAcceptDesc(item.getAcceptDesc());
        dto.setAcceptImages(item.getAcceptImages());
        dto.setRemark(item.getRemark());
        dto.setCreateTime(item.getCreateTime());
        dto.setUpdateTime(item.getUpdateTime());
        dto.setIsPushMsg(item.getIsPushMsg());

        return dto;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean completeItem(ItemCompleteDTO itemCompleteDTO) {
        if (itemCompleteDTO.getItemId() == null) {
            throw new ServiceException("事项ID不能为空");
        }

        ConstructionProjectItemDO item = constructionItemMapper.selectById(itemCompleteDTO.getItemId());
        if (item == null || item.getIsDeleted() == 1) {
            throw new ServiceException("事项不存在");
        }

        // 检查事项状态，只有未开始或进行中的事项才能手动完工
        if (item.getCompletionStatus() == 2) {
            throw new ServiceException("该事项已完成，无需重复完工");
        }

        // 更新事项状态为已完成
        item.setCompletionStatus(2);
        item.setAcceptDesc(itemCompleteDTO.getAcceptDesc());
        
        // 处理验收图片
        if (itemCompleteDTO.getAcceptImages() != null && !itemCompleteDTO.getAcceptImages().isEmpty()) {
            item.setAcceptImages(JSON.toJSONString(itemCompleteDTO.getAcceptImages()));
        }
        
        // 更新备注
        if (itemCompleteDTO.getCompleteRemark() != null && !itemCompleteDTO.getCompleteRemark().trim().isEmpty()) {
            String originalRemark = item.getRemark();
            String newRemark = originalRemark == null ? "" : originalRemark;
            item.setRemark(newRemark + "\n[手动完工] " + itemCompleteDTO.getCompleteRemark());
        }
        
        item.setUpdateTime(LocalDateTime.now());
        item.setUpdateBy(SecurityUtils.getUsername());

        return constructionItemMapper.updateById(item) > 0;
    }
}
